﻿namespace Resharper.Abstractions.Daemons
{
  using System.Diagnostics;
  using JetBrains.Annotations;
  using JetBrains.DocumentModel;
  using JetBrains.ProjectModel;
  using JetBrains.ReSharper.Psi;
  using JetBrains.ReSharper.Psi.CSharp;
  using JetBrains.TextControl;
  using Resharper.Abstractions.Actions;

  /// <summary>Defines the <see cref="FixContext"/> class.</summary>
  public class FixContext
  {
    #region Constructors and Destructors

    /// <summary>Initializes a new instance of the <see cref="FixContext"/> class.</summary>
    /// <param name="solution">The solution.</param>
    /// <param name="document">The document.</param>
    /// <param name="tag">The tag.</param>
    internal FixContext(ISolution solution, IDocument document, object tag)
    {
      this.InternalSolution = solution;
      this.InternalDocument = document;
      this.Tag = tag;
    }

    #endregion

    #region Properties

    /// <summary>
    /// Gets or sets the tag.
    /// </summary>
    /// <value>The tag.</value>
    public object Tag { get; set; }

    /// <summary>
    /// Gets or sets the solution.
    /// </summary>
    /// <value>The solution.</value>
    internal ISolution InternalSolution { get; set; }

    /// <summary>
    /// Gets or sets the internal text control.
    /// </summary>
    /// <value>The internal text control.</value>
    internal ITextControl InternalTextControl { get; set; }

    /// <summary>
    /// Gets the factory.
    /// </summary>
    [NotNull]
    public Factory Factory
    {
      get
      {
        var psiModule = this.GetPsiModule();
        Debug.Assert(psiModule != null, "psiModule != null");

        var factory = CSharpElementFactory.GetInstance(psiModule);
        Debug.Assert(factory != null, "factory != null");

        return new Factory(factory);
      }
    }

    /// <summary>
    /// Gets the project item.
    /// </summary>
    [NotNull]
    public string GetProjectPath()
    {
      var sourceFile = this.InternalDocument.GetPsiSourceFile(this.InternalSolution);

      var projectFile = sourceFile.ToProjectFile();
      if (projectFile == null)
      {
        return string.Empty;
      }

      var project = projectFile.GetProject();
      if (project == null)
      {
        return string.Empty;
      }

      return project.ProjectFileLocation.ToString();
    }

    /// <summary>
    /// Gets the formatter.
    /// </summary>
    public CodeFormatter Formatter
    {
      get
      {
        var psiModule = this.GetPsiModule();
        Debug.Assert(psiModule != null, "psiModule != null");

        var languageType = psiModule.PsiLanguage;
        Debug.Assert(languageType != null, "languageType != null");

        return new CodeFormatter(new Solutions.Solution(this.InternalSolution), languageType);
      }
    }

    /// <summary>Gets the psi module.</summary>
    /// <returns>Returns the psi module.</returns>
    private IPsiModule GetPsiModule()
    {
      return this.InternalDocument.GetPsiSourceFile(this.InternalSolution).GetPsiModule();
    }

    /// <summary>
    /// Gets the internal document.
    /// </summary>
    internal IDocument InternalDocument { get; private set; }

    #endregion
  }
}